package com.hpe.wx.performance.redis.ctrl;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.hpe.wx.performance.redis.domain.KeyValue;
import com.hpe.wx.performance.redis.domain.PerformanceObj;
import com.hpe.wx.performance.redis.domain.Series;
import com.hpe.wx.performance.redis.domain.Xaxis;
import com.hpe.wx.performance.redis.service.PerFormanceService;
import com.hpe.wx.performance.redis.utils.JMXUtils;
import com.hpe.wx.performance.redis.utils.MyMD5Util;
import com.hpe.wx.performance.redis.utils.PropertiesUtils;

import redis.clients.jedis.Tuple;

@Controller
@RequestMapping(value = "/hpe/performance")
public class PerformanceCtrl {
	private static Logger logger = Logger.getLogger(PerformanceCtrl.class.getSimpleName());
	@Autowired
	private PerFormanceService service;

	@RequestMapping(value = "/jmxUrlAdmin", method = RequestMethod.GET)
	public String jmxUrlAdminPage(Locale locale, Model model, String jmxUrl) {
		model.addAttribute("jmxUrl", "欢迎进入");
		Set<Tuple> urls = service.getAllJMXURLs();
		List<KeyValue> jmxUrls = new ArrayList<>();
		for (Tuple t : urls) {
			String[] urlName = t.getElement().split("#");
			jmxUrls.add(new KeyValue(urlName[1], urlName[0]));
		}
		model.addAttribute("jmxUrls", jmxUrls);
		return "hpe/performance/jmxUrlAdmin";
	}

	@RequestMapping(value = "/testPage", method = RequestMethod.GET)
	public String testPage(Locale locale, Model model, String jmxUrl) {
		model.addAttribute("jmxUrl", "欢迎进入");

		return "hpe/performance/testPage";
	}

	@RequestMapping(value = "/exportReport", method = RequestMethod.GET)
	public String exportReport(Locale locale, Model model, String jmxUrl) {
		// To-Do get datas and operating them
		model.addAttribute("mode", "export");
		model.addAttribute("jmxUrl", jmxUrl);

		model.addAttribute("now", getStringFromDate(new Date(), null));
		
		String regEx = "jndi/rmi://([\\w.]*)";
		Pattern pattern = Pattern.compile(regEx);
		Matcher matcher = pattern.matcher(jmxUrl);
		String queueIp = null;
		if(matcher.find()){
			queueIp = matcher.group(1);
			if(!StringUtils.isEmpty(queueIp)){
				System.out.println("------->"+queueIp);
				model.addAttribute("QUEUEIP" , queueIp);
			}
		}

		String jmxName = "";
		Set<Tuple> sss = service.getAllJMXURLs();
		for (Tuple t : sss) {
			jmxName = t.getElement();
			if (jmxName.startsWith(jmxUrl)) {
				model.addAttribute("jmxName", jmxName.split("#")[1]);
				long startTimeStamp = (long) t.getScore();
				Date startDate = new Date(startTimeStamp);
				String startDateTime = getStringFromDate(startDate, null);

				model.addAttribute("datetimeStart", startDateTime);
				model.addAttribute("now", getStringFromDate(new Date(), null));
			}
		}
		return "hpe/performance/dynamicReport";
	}

	@RequestMapping(value = "/dynamicReport", method = RequestMethod.GET)
	public String dynamicReport(Locale locale, Model model, String jmxUrl) {
		String regEx = "jndi/rmi://([\\w.]*)";
		Pattern pattern = Pattern.compile(regEx);
		Matcher matcher = pattern.matcher(jmxUrl);
		String queueIp = null;
		if(matcher.find()){
			queueIp = matcher.group(1);
			if(!StringUtils.isEmpty(queueIp)){
				System.out.println("------->"+queueIp);
				model.addAttribute("QUEUEIP" , queueIp);
			}
		}
		
		
		model.addAttribute("jmxUrl", jmxUrl);

		String jmxName = "";
		Set<Tuple> sss = service.getAllJMXURLs();
		for (Tuple t : sss) {
			jmxName = t.getElement();
			if (jmxName.startsWith(jmxUrl)) {
				model.addAttribute("jmxName", jmxName.split("#")[1]);

				long startTimeStamp = (long) t.getScore();
				Date startDate = new Date(startTimeStamp);
				String startDateTime = getStringFromDate(startDate, null);

				model.addAttribute("datetimeStart", startDateTime);
				model.addAttribute("now", getStringFromDate(new Date(), null));
			}
		}
		return "hpe/performance/dynamicReport";
	}

	@ResponseBody
	@RequestMapping(value = "/checkJmxUrl", method = RequestMethod.GET)
	public Map<String, Object> checkJmxUrl(Locale locale, Model model, String jmxUrl) {
		jmxUrl = jmxUrl.trim();
		Map<String, Object> res = JMXUtils.checkJmxUrlUseable(jmxUrl);
		return res;
	}

	@ResponseBody
	@RequestMapping(value = "/addDelJmxUrl", method = RequestMethod.GET)
	public Map<String, Object> addDelJmxUrl(Locale locale, Model model, String jmxUrl, String cmd, String jmxName) {
		Map<String, Object> res = new HashMap<>();
		if (!StringUtils.isEmpty(jmxName)) {
			jmxName = jmxName.trim();
		}
		if (!StringUtils.isEmpty(jmxUrl)) {
			jmxUrl = jmxUrl.trim();
		}
		res.put("status", "The operation on #" + jmxUrl + "# was successfully");
		boolean success = true;
		Set<Tuple> urlAndNames = service.getAllJMXURLs();
		if ("add".equals(cmd)) {
			for (Tuple t : urlAndNames) {
				String temp = t.getElement();
				String[] nameAndUrl = temp.split("#");
				if (jmxUrl.equals(nameAndUrl[0]) || jmxName.equals(nameAndUrl[1])) {
					success = false;
					res.clear();
					res.put("status", "The #" + jmxUrl + "# is exist");
				}
			}
			if (success) {
				flushDbByUrl(jmxUrl);
				service.addJMXURL(jmxUrl + "#" + jmxName);
				logger.info("############add: " + jmxUrl);
				logger.debug("############add: " + jmxUrl);
			}
		} else {
			service.removeJMXURL(jmxUrl + "#" + jmxName);
			flushDbByUrl(jmxUrl);
			logger.info("############del: " + jmxUrl);
		}
		return res;
	}

	private Map<String, Object> flushDbByUrl(String jmxUrl) {
		Map<String, Object> res = new HashMap<>();

		String md5jmxUrl = MyMD5Util.string2MD5(jmxUrl);
		Long cpuRecordCount = service.removeKey("CPU:" + md5jmxUrl);
		logger.warn("Delete a key, name is " + "CPU:" + md5jmxUrl);
		Long memRecordCount = service.removeKey("MEM:" + md5jmxUrl);
		logger.warn("Delete a key, name is " + "MEM:" + md5jmxUrl);
		Long jvmRecordCount = service.removeKey("JVM:" + md5jmxUrl);
		logger.warn("Delete a key, name is " + "JVM:" + md5jmxUrl);
		Long timestampRecordCount = service.removeKey("TIMESTAMP:" + md5jmxUrl);
		logger.warn("Delete a key, name is " + "TIMESTAMP:" + md5jmxUrl);
		Long heapusedRecordCount = service.removeKey("HEAPUSED:" + md5jmxUrl);
		logger.warn("Delete a key, name is " + "HEAPUSED:" + md5jmxUrl);
		Long heapCommittedRecordCount = service.removeKey("HEAPCOMMITTED:" + md5jmxUrl);
		logger.warn("Delete a key, name is " + "HEAPCOMMITTED:" + md5jmxUrl);
		// logger.info("flushdb: " + jmxUrl);

		res.put("cpuRecordCount", cpuRecordCount);
		res.put("memRecordCount", memRecordCount);
		res.put("jvmRecordCount", jvmRecordCount);
		res.put("timestampRecordCount", timestampRecordCount);
		res.put("heapusedRecordCount", heapusedRecordCount);
		res.put("heapCommittedRecordCount", heapCommittedRecordCount);
		logger.info("flushdb: " + res);
		return res;
	}

	@ResponseBody
	@RequestMapping(value = "/getDynamicData", method = RequestMethod.GET)
	public PerformanceObj getDynamicData(Locale locale, Model model, String jmxUrl, String dateStart, String dateEnd) {// jmxUrl
		PerformanceObj resPerformanceObj = new PerformanceObj();

		logger.info("startTime: " + dateStart + "  endTime: " + dateEnd);

		String md5jmxUrl = MyMD5Util.string2MD5(jmxUrl);

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");
		long scoreStart = 0;
		long scoreEnd = 0;
		try {
			scoreStart = sdf.parse(dateStart).getTime();
			scoreEnd = 0;
			if (StringUtils.isEmpty(dateEnd)) {
				scoreEnd = (new Date()).getTime();
			} else {
				scoreEnd = sdf.parse(dateEnd).getTime();
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}

		// cpu
		List<Object> cpuData = service.getDataListByScore("CPU:" + md5jmxUrl, scoreStart, scoreEnd, 0);

		// mem
		List<Object> memData = service.getDataListByScore("MEM:" + md5jmxUrl, scoreStart, scoreEnd, 0);

		// jvm
		List<Object> jvmData = service.getDataListByScore("JVM:" + md5jmxUrl, scoreStart, scoreEnd, 0);

		// heap used
		List<Object> heapUsedData = service.getDataListByScore("HEAPUSED:" + md5jmxUrl, scoreStart, scoreEnd, 0);

		// heap committed
		List<Object> heapCommittedData = service.getDataListByScore("HEAPCOMMITTED:" + md5jmxUrl, scoreStart, scoreEnd,
				0);

		// timestamp
		List<Object> timeStampData = service.getDataListByScore("TIMESTAMP:" + md5jmxUrl, scoreStart, scoreEnd, 0);

		logger.info(resPerformanceObj);

		/**/// get Data
		List<Series> seriesList = new ArrayList<Series>();

		Xaxis xaxis = new Xaxis();
		xaxis.setType("category");

		// timestamp
		// List<String> xaxisData = service.getDataList("TIMESTAMP:" +
		// md5jmxUrl, 0, -1);

		if (timeStampData.size() > 0) {
			List<String> formatXaxisData = new ArrayList<>();
			for (Object timeStr : timeStampData) {
				formatXaxisData.add(getFormatDatefromTimeStamp(((Double) (timeStr)).longValue(), null));
			}
			xaxis.setData(formatXaxisData);

			List<Xaxis> xaxisData = new ArrayList<>();
			xaxisData.add(xaxis);
			resPerformanceObj.setXaxis(xaxisData);

			// cpu index 0
			Series seriesCpu = new Series();
			seriesCpu.setName("CPU");
			seriesCpu.setType("line");

			seriesCpu.setData(cpuData);
			seriesList.add(seriesCpu);

			// mem index 1
			Series seriesMem = new Series();
			seriesMem.setName("MEM");
			seriesMem.setType("line");

			seriesMem.setData(memData);
			seriesList.add(seriesMem);

			// jvm index 2
			Series seriesJvm = new Series();
			seriesJvm.setName("JVM");
			seriesJvm.setType("line");

			seriesJvm.setData(jvmData);
			seriesList.add(seriesJvm);

			// heap used index 3
			Series seriesHeapUsed = new Series();
			seriesHeapUsed.setName("HEAPUSED");
			seriesHeapUsed.setType("line");

			seriesHeapUsed.setData(heapUsedData);
			seriesList.add(seriesHeapUsed);

			// heap committed index 4
			Series seriesHeapCommitted = new Series();
			seriesHeapCommitted.setName("HEAPCOMMITTED");
			seriesHeapCommitted.setType("line");

			seriesHeapCommitted.setData(heapCommittedData);
			seriesList.add(seriesHeapCommitted);

			resPerformanceObj.setSeriesList(seriesList);

			Map<String, Object> lastRecord = new HashMap<>();
			lastRecord.put("CPUSIZE", cpuData.size());
			lastRecord.put("CPUPER", cpuData.get(cpuData.size() - 1));

			lastRecord.put("MEMSIZE", memData.size());
			lastRecord.put("MEMPER", memData.get(memData.size() - 1));

			lastRecord.put("JVMSIZE", jvmData.size());
			lastRecord.put("JVMPER", jvmData.get(jvmData.size() - 1));

			lastRecord.put("HEAPUSEDSIZE", heapUsedData.size());
			lastRecord.put("HEAPUSED", heapUsedData.get(heapUsedData.size() - 1));

			lastRecord.put("HEAPCOMMITTEDSIZE", heapCommittedData.size());
			lastRecord.put("HEAPCOMMITTED", heapCommittedData.get(heapCommittedData.size() - 1));

			lastRecord.put("TIMESTAMPDATASIZE", timeStampData.size());

			resPerformanceObj.setLastRecord(lastRecord);
		} else {
			resPerformanceObj = null;
		}

		return resPerformanceObj;
	}

	@ResponseBody
	@RequestMapping(value = "/exportReport2File", method = RequestMethod.GET)
	public Map<String, Object> makeReportData(HttpServletRequest request, HttpServletResponse response, Locale locale,
			Model model, String jmxUrl, String dateStart, String dateEnd) {
		Map<String, Object> res = new HashMap<>();
		// List<String> cpuData = service.zAddData("CPU:" + md5jmxUrl,
		// currentTimeStamp, cpuper + ":" + currentTimeStamp);

		List<Object> cpuData = getDataByDate(jmxUrl, "CPU", dateStart, dateEnd);

		List<Object> memData = getDataByDate(jmxUrl, "MEM", dateStart, dateEnd);

		List<Object> jvmData = getDataByDate(jmxUrl, "JVM", dateStart, dateEnd);

		List<Object> heapusedData = getDataByDate(jmxUrl, "HEAPUSED", dateStart, dateEnd);

		List<Object> heapcommittedData = getDataByDate(jmxUrl, "HEAPCOMMITTED", dateStart, dateEnd);

		List<Object> timeStampData = getDataByDate(jmxUrl, "TIMESTAMP", dateStart, dateEnd);

		logger.info("The data will export: " + cpuData + memData + jvmData + heapusedData + heapcommittedData
				+ timeStampData);

		/////////////////////////////////////////////////
		// 创建Excel的工作书册 Workbook,对应到一个excel文档
		HSSFWorkbook wb = new HSSFWorkbook();

		// 创建Excel的工作sheet,对应到一个excel文档的tab
		HSSFSheet sheet = wb.createSheet("useage");

		// 设置excel每列宽度
		for (int i = 0; i < 20; i++) {
			// sheet.autoSizeColumn(i);
			sheet.setColumnWidth(i, 20 * 256);
		}

		// The first line of the report
		HSSFRow titleRow = sheet.createRow(0);

		HSSFCell timeCell = titleRow.createCell(0);
		timeCell.setCellValue("DateTime");

		HSSFCell cpuCell = titleRow.createCell(1);
		cpuCell.setCellValue("cpu(%)");

		HSSFCell memCell = titleRow.createCell(2);
		memCell.setCellValue("mem(%)");

		HSSFCell jvmCell = titleRow.createCell(3);
		jvmCell.setCellValue("jvm(%)");

		HSSFCell heapUsedCell = titleRow.createCell(4);
		heapUsedCell.setCellValue("heapUsed(mb)");

		HSSFCell heapCommittedCell = titleRow.createCell(5);
		heapCommittedCell.setCellValue("heapCommitted(mb)");

		for (int rowNumber = 1; rowNumber < cpuData.size(); rowNumber++) {// loop
																			// the
																			// rows
			HSSFRow row = sheet.createRow(rowNumber);// create a row
			for (int columnNumber = 0; columnNumber < 6; columnNumber++) {// loop
																			// the
																			// columns
				HSSFCell cell = row.createCell(columnNumber);// create a cell
				String cellValue = "";
				if (columnNumber == 0) {//
					cellValue = getStringFromDate(new Date(((Double)timeStampData.get(rowNumber - 1)).intValue()), null);
				} else if (columnNumber == 1) {
					// cpu
					cellValue = cpuData.get(rowNumber - 1).toString();
				} else if (columnNumber == 2) {
					// mem
					cellValue = memData.get(rowNumber - 1).toString();
				} else if (columnNumber == 3) {
					// cou
					cellValue = jvmData.get(rowNumber - 1).toString();
				} else if (columnNumber == 4) {
					// cou
					cellValue = heapusedData.get(rowNumber - 1).toString();
				} else if (columnNumber == 5) {
					// cou
					cellValue = heapcommittedData.get(rowNumber - 1).toString();
				}
				cell.setCellValue(cellValue);
			}
		}
		FileOutputStream os = null;
		String storePath = PropertiesUtils.getProperty("report.storepath");
		File f = new File(storePath);
		if (!f.exists()) {
			f.mkdirs();
		}
		String fileName = storePath + dateStart.replace("/", "-").replace(":", "_").replace(" ", ".") + "--"
				+ dateEnd.replace("/", "-").replace(":", "_").replace(" ", ".") + ".xls";
		try {
			os = new FileOutputStream(fileName);
			wb.write(os);

			res.put("status", "success");
			res.put("message", "the report was expored successfly");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			res.put("status", "faild");
			res.put("message", "can not find the file");
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			res.put("status", "faild");
			res.put("message", "IO exception");
			e.printStackTrace();
		} finally {
			try {
				if (null != os) {
					os.close();
				}
				if (null != wb) {
					wb.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		File file2Download = new File(fileName);
		InputStream fis = null;
		OutputStream toClient = null;
		try {
			if (null != file2Download && file2Download.exists() && file2Download.length() > 0) {

				// 以流的形式下载文件。
				fis = new BufferedInputStream(new FileInputStream(file2Download));

				/**
				 * 
				 * 这里将文件按照每次1024个字节读取到一个list中
				 **/
				int c;
				byte[] buffer = new byte[1024];
				List<Byte> listTemp = new ArrayList<Byte>();
				while ((c = fis.read(buffer)) != -1) {// 这里的byte 数组怎么处理？
					for (int i = 0; i < c; i++) {// out.write(buffer[i]);
						listTemp.add(buffer[i]);
					}
					buffer = new byte[1024];// 重新覆盖掉以前的内容
				}
				fis.close();
				// /////////////读取完毕

				/**
				 * 
				 * 这里将文件按照每次1个字节向浏览器输出文件
				 **/
				// 清空response
				response.reset();
				fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
				if (request.getHeader("User-Agent").toLowerCase().indexOf("firefox") > 0) {
					fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");// firefox浏览器
				} else if (request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0) {
					fileName = URLEncoder.encode(fileName, "UTF-8");// IE浏览器
				} else {// 其他浏览器 chrome 之类的 牛逼的写法
					fileName = URLEncoder.encode(fileName, "UTF-8");
				}

				// 设置response的Header
				response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");//
				response.addHeader("Content-Length", "" + file2Download.length());

				toClient = new BufferedOutputStream(response.getOutputStream());
				response.setContentType("application/octet-stream");

				// while
				for (int i = 0; i < listTemp.size(); i++) {
					toClient.write(listTemp.get(i));
				}
				toClient.flush();
				toClient.close();
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				if (null != toClient) {
					toClient.close();
				}
				if (null != fis) {
					fis.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return res;
	}

	/**
	 * @param jmxUrl
	 * @param key
	 * @param datestart
	 * @param dateEnd
	 * @return
	 */
	private List<Object> getDataByDate(String jmxUrl, String key, String dateStart, String dateEnd) {
		List<Object> res = new ArrayList<>();
		String md5jmxUrl = MyMD5Util.string2MD5(jmxUrl);

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");
		Date startDate = null;
		Date endDate = null;
		try {
			startDate = sdf.parse(dateStart);
			endDate = sdf.parse(dateEnd);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		res = service.getDataListByScore(key + ":" + md5jmxUrl, startDate.getTime(), endDate.getTime(), 0);

		return res;
	}

	private String getStringFromDate(Date d, String formatString) {
		SimpleDateFormat sdf = null;
		if (StringUtils.isEmpty(formatString)) {
			sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");
		} else {
			sdf = new SimpleDateFormat(formatString);
		}
		if (null == d) {
			d = new Date();
		}
		return sdf.format(d);
	}

	private Date getDateFromString(String str) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");
		Date d = null;
		try {
			d = sdf.parse(str);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return d;
	}

	private String getFormatDatefromTimeStamp(long timestamp, String format) {
		Date d = new Date(timestamp);
		if (StringUtils.isEmpty(format))
			format = "yy/MM/dd HH:mm";
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(d);
	}

}
